package util;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.net.URL;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;
import java.util.Locale;

import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

import core.Criterion;
import core.CriterionType;
import core.Dmu;
import core.DmuList;
import core.Optimization;
import core.Optimizer;
import core.PdmOptimization;
import facilitator.StoreItem;
import javax.swing.ToolTipManager;

public class Util {
	
	private static FileWriter out;
	private static FileWriter log;
	private static int standardRoundingPrecision = -1;
	private static int standardTruncationPrecision = 12;
	
	public static double roundUp(double val) {
		return roundUp(val, standardRoundingPrecision);
	}
	public static double[] RoundUp(double[] val) {
		return roundUp(val, standardRoundingPrecision);
	}
	public static double[] roundUp(double[] val, int precision) {
		double[] temp = val.clone();
		for(int i = 0; i < val.length;i++){
			temp[i] = Util.roundUp(val[i], precision);
		}
		return temp;
	}
	public static double roundUp(double val, int precision) {
		if(precision == -1){
			return val;
		}
		else{
			BigDecimal bd = new BigDecimal(val);
			bd = bd.setScale(precision, BigDecimal.ROUND_UP);
			return bd.doubleValue();
		}
	}
    public static float roundUp(float val, int precision) {
		if(precision == -1){
			return val;
		}
		else{
			BigDecimal bd = new BigDecimal(val);
			bd = bd.setScale(precision, BigDecimal.ROUND_UP);
			return bd.floatValue();
		}
	}
    public static double roundHalfUp(double val, int precision) {
		if(precision == -1){
			return val;
		}
		else{
			BigDecimal bd = new BigDecimal(val);
			bd = bd.setScale(precision, BigDecimal.ROUND_HALF_UP);
			return bd.doubleValue();
		}
	}
	public static double[] truncate(double[] val) {
		double[] temp = val.clone();
		for(int i = 0; i < val.length;i++){
			temp[i] = Util.truncate(val[i], standardTruncationPrecision);
		}
		return temp;
	}
	public static double truncate(double val) {
		return truncate(val, Util.standardTruncationPrecision);
	}
	public static double truncate(double val, int precision) {
		if(precision == -1){
			return val;
		}
		else{
			BigDecimal bd = new BigDecimal(val);
			bd = bd.setScale(precision, BigDecimal.ROUND_DOWN);
			return bd.doubleValue();
		}
	}
    public static boolean isPowerTwo(int o, int upperbound){

        for(int i=1;i<upperbound;i++){
            if(Math.pow(2, i) == o){
                return true;
            }
        }
        return false;
    }
	public static double getPercent(double val, double baseWeight){
        return Util.truncate(val/baseWeight*100,0);
	}
	public static String getTimeStamp(){
		return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(Calendar.getInstance().getTime());
	}
	public static void initializeFileWriter(String filename){
		try {
			out = new FileWriter(filename, false);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	public static void log(Object text){
		try {
			if(log==null){
				log = new FileWriter("log/log_" + System.currentTimeMillis() + ".log",true);
			}
	        log.write(text.toString().replace('.', ','));
	        log.write(System.getProperty("line.separator"));
            log.flush();
	        Util.print(text);
	    } catch (IOException e) {
	    	Util.print(e.toString());
	    }
	}
	public static void writeToFile(Object text){
		try {
	        out.write(text.toString().replace('.', ','));
	        out.write(System.getProperty("line.separator"));
	        out.flush();
	    } catch (IOException e) {
	    	Util.print(e.toString());
	    }
	}
	public static void closeFileWriter()
	{
		try {
			out.flush();
			out.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	public static void print(Object text) {
		System.out.println(text);
        System.out.flush();
	}

	/*public static int[] getDirections(double[] relUrmWeights, Optimization deaOptimizationResults){
		try{
			int[] directions = new int[deaOptimizationResults.getOptimizationInput().dmuList.outputSize];
			for(int x = deaOptimizationResults.getOptimizationInput().dmuList.inputSize;x < deaOptimizationResults.getOptimizationInput().dmuList.get(deaOptimizationResults.getOptimizationInput().objectiveDmu).criteria.size();x++){
				//Util.print(((PdmOptimizationInput)input).urmWeights[x-input.dmuList.inputSize]);
				if (deaOptimizationResults.dmuList.get(deaOptimizationResults.getOptimizationInput().objectiveDmu).criteria.get(x).weighting / 
						deaOptimizationResults.dmuList.get(deaOptimizationResults.getOptimizationInput().objectiveDmu).criteria.get(deaOptimizationResults.getOptimizationInput().dmuList.inputSize).weighting >
						relUrmWeights[x-deaOptimizationResults.getOptimizationInput().dmuList.inputSize]) {
					directions[x-deaOptimizationResults.getOptimizationInput().dmuList.inputSize] = 1;
				} else {
					directions[x-deaOptimizationResults.getOptimizationInput().dmuList.inputSize] = -1;
				}
			}
			return directions;
			}catch (Exception e) {
				e.printStackTrace();
				return null;
			}
	}*/
	@SuppressWarnings("deprecation")
	public static DmuList LoadFile(String filename) throws NumberFormatException,
			IOException {

		URL Datastream = new File(filename).toURL();
		BufferedReader t = new BufferedReader(new InputStreamReader(Datastream
				.openStream()));
		String currLine;
		DmuList temp = new DmuList();
		List<String> inputs = new ArrayList<String>();
		List<String> outputs = new ArrayList<String>();

		// Header ROW
		currLine = t.readLine();

		String[] inout = currLine.split(";&;");
		for (String i : inout[0].split(";")) {
			inputs.add(i);
		}
		temp.inputSize = inputs.size();
		for (String o : inout[1].split(";")) {
			outputs.add(o);
		}
		temp.outputSize = outputs.size();
		int p = 0;
		// All value Rows
		while ((currLine = t.readLine()) != null) {
			// Debug.WriteLine(currLine);
			inout = currLine.split(";&;");
			Dmu curr = new Dmu();
			curr.id = ++p;

			String[] ins = inout[0].split(";");

			// add all input criteria to actual dmu
			for (int r = 0; r < inputs.size(); r++) {
				curr.criteria.add(new Criterion(CriterionType.Input, inputs
						.get(r), Double.parseDouble(ins[r])));
			}
			// add all output criteria to actual dmu
			String[] outs = inout[1].split(";");
			for (int r = 0; r < outputs.size(); r++) {
				curr.criteria.add(new Criterion(CriterionType.Output, outputs
						.get(r), Double.parseDouble(outs[r])));
			}
			temp.add(curr);
		}
		return temp;
	}
	public static void setLookAndFeel(){
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            ToolTipManager.sharedInstance().setInitialDelay(1);
            ToolTipManager.sharedInstance().setDismissDelay(5000);
			//UIManager.setLookAndFeel(UIManager.getInstalledLookAndFeels()[1].getClassName());
			//Util.print(Arrays.toString(UIManager.getInstalledLookAndFeels()));
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (UnsupportedLookAndFeelException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	public static Connection getConnection() throws Exception {
		Driver d = (Driver)Class.forName
		("sun.jdbc.odbc.JdbcOdbcDriver").newInstance();
		Connection c = DriverManager.getConnection(
		"jdbc:odbc:Driver={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=E:\\Privat\\Doktorat\\PDMDatenauswertung\\test.accdb"
		);
		return c;
	}
	public static void enableWebStart() {
		try {
			Util.loadNativeLibs();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	private static void loadNativeLibs() throws IOException, Exception{
		String os = System.getProperty( "os.name" );
        System.out.println("loading " + os + " native libraries ..");
        if ( os.startsWith( "Windows" ) )
        {
            // order matters here!
            // load those libs that are required by other libs first!
            System.out.print( "lpsolve55.dll .. " );
            // drop ".dll" suffix here
            System.loadLibrary("lpsolve55");
            System.out.println( "OK" );

            System.out.print( "lpsolve55j.dll .. " );
            System.loadLibrary( "lpsolve55j" );
            System.out.println( "OK" );
        } else if ( os.equals( "Linux" ) )
        {
            System.out.print( "liblpsolve55.so .. " );
            // drop "lib" prefix and ".so" suffix
            System.loadLibrary( "lpsolve55" );
            System.out.println( "OK" );

            System.out.print( "liblpsolve55j.so .. " );
            System.loadLibrary( "lpsolve55j" );
            System.out.println( "OK" );
        } else
            throw new Exception( "OS '" + os + "' not yet supported." );

		extractFile("PDM1.csv");
		//System.loadLibrary("lpsolve55");
		//System.loadLibrary("lpsolve55j");
	}
	/**
	 * Extracts native dlls from jars and copies to current dir
	 * @throws IOException
	 */
	private static void copyLibs() throws IOException{
		File eins = new File("lpsolve55.dll");
		File zwei = new File("lpsolve55j.dll");
		
		InputStream eis = Thread.currentThread().getContextClassLoader().getResourceAsStream("lpsolve55.dll");
		
		FileOutputStream fos = new FileOutputStream(eins);
		byte[] x = new byte[8192];
		int read = 0;
		while ( (read = eis.read(x)) > 0)
		{
			fos.write(x, 0, read);
		}
		fos.close();
		eis.close();	
		
		eis = Thread.currentThread().getContextClassLoader().getResourceAsStream("lpsolve55j.dll");
		fos = new FileOutputStream(zwei);
		x = new byte[8192];
		read = 0;
		while ( (read = eis.read(x)) > 0)
		{
			fos.write(x, 0, read);
		}
		fos.close();
		eis.close();
	}
	private static void extractFile(String filename) throws IOException{
		
		InputStream eis = Thread.currentThread().getContextClassLoader().getResourceAsStream(filename);
		
		FileOutputStream fos = new FileOutputStream(filename);
		byte[] x = new byte[8192];
		int read = 0;
		while ( (read = eis.read(x)) > 0)
		{
			fos.write(x, 0, read);
		}
		fos.close();
		eis.close();	
	}
	/*private static void loadNativeLibs() throws IOException, InterruptedException{
		//copyLibs();
		String file1 = extractToTempFile("lpsolve55.dll");
		Util.print("lpsolve55.dll => " + file1);
		File oldFile = new File(file1);
		File neu = new File(oldFile.getPath().replace(oldFile.getName(),"lpsolve55.dll"));
		oldFile.renameTo(neu);
		Util.print("lpsolve55.dll => " + neu.getPath());
		System.load(neu.getPath());
		
		
		String file2 = extractToTempFile("lpsolve55j.dll");
		Util.print("lpsolve55j.dll => " + file2);
		oldFile = new File(file2); 
		neu = new File(oldFile.getPath().replace(oldFile.getName(),"lpsolve55j.dll"));
		oldFile.renameTo(neu);
		Util.print("lpsolve55j.dll => " + neu.getPath());
		System.load(neu.getPath());
	}*/
	private static String extractToTempFile(String filename) throws IOException{
		
		InputStream eis = Thread.currentThread().getContextClassLoader().getResourceAsStream(filename);
		File temp = File.createTempFile("lpsolve", ".dll");
		FileOutputStream fos = new FileOutputStream(temp);
		byte[] x = new byte[8192];
		int read = 0;
		while ( (read = eis.read(x)) > 0)
		{
			fos.write(x, 0, read);
		}
		fos.close();
		eis.close();	
		return temp.getPath();
	}
}
